﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Tomahawk.Runtime.Rendering.Materials
{
    #region SAS Parameter Builder
    public static class SASParameterBuilder
    {
        public static Dictionary<string, Type> table = new Dictionary<string, Type>()
        {
            {"STANDARDSGLOBAL", typeof(SASScriptParameter)},
            {"TIME", typeof(SASTimeParameter)},
            {"ELAPSEDTIME", typeof(SASTimeParameter)},
            {"POSITION", typeof(SASPositionParameter)},
            {"SPECULAR", typeof(SASSpecularParameter)},
            {"AMBIENT", typeof(SASAmbientParameter)},
            {"RENDERCOLORTARGET", typeof(SASRenderTargetParameter)},
            {"RENDERDEPTHSTENCILTARGET", typeof(SASDepthStencilParameter)},
            {"VIEWPORTPIXELSIZE", typeof(SASViewportPixelSizeParameter)},
            {"WORLD", typeof(SASTransformParameter)},
            {"VIEW", typeof(SASTransformParameter)},
            {"WORLDVIEW", typeof(SASTransformParameter)},
            {"VIEWPROJECTION", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTION", typeof(SASTransformParameter)},
            {"WORLDINVERSE", typeof(SASTransformParameter)},
            {"VIEWINVERSE", typeof(SASTransformParameter)},
            {"PROJECTIONINVERSE", typeof(SASTransformParameter)},
            {"WORLDVIEWINVERSE", typeof(SASTransformParameter)},
            {"VIEWPROJECTIONINVERSE", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTIONINVERSE", typeof(SASTransformParameter)},
            {"WORLDTRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWTRANSPOSE", typeof(SASTransformParameter)},
            {"PROJECTIONTRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWTRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWPROJECTIONTRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTIONTRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"PROJECTIONINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWPROJECTIONINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTIONINVERSETRANSPOSE", typeof(SASTransformParameter)}
        };

        public static SASParameter Build(EffectParameter parameter)
        {
            Type type = null;
            SASParameter sasParameter = null;
            if ((parameter.Semantic != null) && (table.TryGetValue(parameter.Semantic.ToUpper(), out type)))
            {
                sasParameter = Activator.CreateInstance(type) as SASParameter;
                sasParameter.Initialize(parameter);
            }
            else
            {
                sasParameter = new SASParameter();
                sasParameter.Initialize(parameter);
            }
            return sasParameter;
        }
    }
    #endregion

    #region SAS Parameter Exceptions
    public class SASWrongParameterTypeException : Exception
    {
    }
    public class SASUninitializedParameterException : Exception
    {
    }
    #endregion

    #region SASTarget
    public sealed class SASTarget
    {
        public enum TargetType
        {
            Unknown,
            Light0
        }

        private TargetType type;
        public TargetType Type { get { return type; } }

        public SASTarget(EffectParameter parameter)
        {
            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                if (annotation.Name.ToUpper() == "OBJECT")
                {
                    string value = annotation.GetValueString().ToUpper();
                    switch (value)
                    {
                        case "LIGHT0":
                        case "POINTLIGHT0":
                        case "SPOTLIGHT0": type = TargetType.Light0; break;
                        default: type = TargetType.Unknown; break;
                    }
                }
            }
        }
    }
    #endregion

    #region SAS Parameter
    public class SASParameter
    {
        protected EffectParameter parameter;
        public string Name
        {
            get 
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                return parameter.Name;
            }
        }

        protected bool autoValue = false;
        public bool AutoValue { get { return autoValue; } }

        #region Parameter Value
        public enum SASParameterType
        {
            SASUndefined,
            SASBool,
            SASInt,
            SASFloat,
            SASString,
            SASVector,
            SASQuaternion,
            SASMatrix,
            SASMatrixArray,
            SASTexture,
        };

        protected object value = null;

        protected SASParameterType sasType = SASParameterType.SASUndefined;
        public SASParameterType Type
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (sasType == SASParameterType.SASUndefined) sasType = GetSASType();
                return sasType;
            }
        }

        public bool BoolValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASBool) throw new SASWrongParameterTypeException(); 
                try { if (value == null) value = parameter.GetValueBoolean(); }
                catch { throw new SASWrongParameterTypeException(); }
                return (Boolean) value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); } 
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public float FloatValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASFloat) throw new SASWrongParameterTypeException();
                try { if (value == null) value = parameter.GetValueSingle(); }
                catch { throw new SASWrongParameterTypeException(); }
                return (float)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public int IntValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASInt) throw new SASWrongParameterTypeException();
                try { if (value == null) value = parameter.GetValueInt32(); }
                catch { throw new SASWrongParameterTypeException(); }
                return (int)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public Matrix MatrixValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASMatrix) throw new SASWrongParameterTypeException();
                try { if (value == null) value = parameter.GetValueMatrix(); }
                catch { throw new SASWrongParameterTypeException(); }
                return (Matrix)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public Matrix[] MatrixArrayValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASMatrixArray) throw new SASWrongParameterTypeException();
                try { if (value == null) value = parameter.GetValueMatrixArray(parameter.Elements.Count); }
                catch { throw new SASWrongParameterTypeException(); }
                return (Matrix[])value;
                throw new NotImplementedException();
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
                throw new NotImplementedException();
            }
        }
        public string StringValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASString) throw new SASWrongParameterTypeException();
                try { if (value == null) value = parameter.GetValueString(); }
                catch { throw new SASWrongParameterTypeException(); }
                return (string)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public Texture TextureValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASTexture) throw new SASWrongParameterTypeException();
                try
                {
                    if (value == null)
                    {
                        switch (parameter.ParameterType)
                        {
                            case EffectParameterType.Texture2D: value = parameter.GetValueTexture2D(); break;
                            case EffectParameterType.Texture3D: value = parameter.GetValueTexture3D(); break;
                            case EffectParameterType.TextureCube: value = parameter.GetValueTextureCube(); break;
                            default: throw new SASWrongParameterTypeException();
                        }
                    }
                }
                catch { throw new SASWrongParameterTypeException(); }
                return (Texture)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public Vector4 VectorValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASVector) throw new SASWrongParameterTypeException();
                try 
                {
                    if (value == null)
                    {
                        switch (parameter.ColumnCount)
                        {
                            case 2:
                                {
                                    Vector2 data = parameter.GetValueVector2();
                                    value = new Vector4(data.X, data.Y, 0.0f, 0.0f);
                                } break;
                            case 3:
                                {
                                    Vector3 data = parameter.GetValueVector3();
                                    value = new Vector4(data.X, data.Y, data.Z, 0.0f);
                                } break;
                            case 4: value = parameter.GetValueVector4(); break;
                            default: throw new SASWrongParameterTypeException();
                        }
                    }
                }
                catch { throw new SASWrongParameterTypeException(); }
                return (Vector4)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try 
                {
                    switch (parameter.ColumnCount)
                    {
                        case 2: parameter.SetValue(new Vector2(value.X, value.Y)); break;
                        case 3: parameter.SetValue(new Vector3(value.X, value.Y, value.Z)); break;
                        case 4: parameter.SetValue(value); break;
                        default: throw new SASWrongParameterTypeException();
                    }
                }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        public Quaternion QuaternionValue
        {
            get
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                if (Type != SASParameterType.SASVector) throw new SASWrongParameterTypeException();
                try { if (value == null) value = parameter.GetValueQuaternion(); }
                catch { throw new SASWrongParameterTypeException(); }
                return (Quaternion)value;
            }
            set
            {
                if (parameter == null) throw new SASUninitializedParameterException();
                try { parameter.SetValue(value); }
                catch { throw new SASWrongParameterTypeException(); }
                this.value = value;
            }
        }
        #endregion

        private SASParameterType GetSASType()
        {
            if (parameter != null)
            {
                switch (parameter.ParameterType)
                {
                    case EffectParameterType.Bool:
                        {
                            return SASParameterType.SASBool;
                        }
                    case EffectParameterType.Int32:
                        {
                            return SASParameterType.SASInt;
                        }
                    case EffectParameterType.Single:
                        {
                            switch (parameter.ParameterClass)
                            {
                                case EffectParameterClass.Scalar: return SASParameterType.SASFloat;
                                case EffectParameterClass.Vector: return SASParameterType.SASVector;
                                case EffectParameterClass.MatrixColumns:
                                case EffectParameterClass.MatrixRows:
                                    {
                                        if (parameter.Elements.Count > 0) return SASParameterType.SASMatrixArray;
                                        return SASParameterType.SASMatrix;
                                    }
                                default: throw new NotImplementedException();
                            }
                        }
                    case EffectParameterType.String:
                        {
                            return SASParameterType.SASString;
                        }
                    case EffectParameterType.Texture:
                        {
                            return SASParameterType.SASTexture;
                        }
                }
            }

            return SASParameterType.SASUndefined;
        }

        public virtual bool Initialize(EffectParameter parameter)
        {
            this.parameter = parameter;
            return true;
        }

        public virtual bool Update(SASEffectEnvironment environment)
        {
            return true;
        }
    }
    #endregion

    #region SASScriptParameter
    public class SASScriptParameter : SASParameter
    {
        public enum ScriptClassType
        {
            Object,
            Scene,
            ObjectOrScene
        }

        public enum ScriptOrderType
        {
            Standard,
            Preprocess,
            Postprocess
        }

        public enum ScriptOutputType
        {
            Color
        }

        #region Properties
        protected SASScript script;

        protected float scriptVersion;
        public float ScriptVersion { get { return scriptVersion; } }

        protected ScriptClassType scriptClass;
        public ScriptClassType ScriptClass { get { return scriptClass; } }

        protected ScriptOrderType scriptOrder;
        public ScriptOrderType ScriptOrder { get { return scriptOrder; } }

        protected ScriptOutputType scriptOutput;
        public ScriptOutputType ScriptOutput { get { return scriptOutput; } } 
        #endregion

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.scriptVersion = FloatValue;
            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                string name = annotation.Name.ToUpper();
                string value = annotation.GetValueString().ToUpper();

                switch (name.ToUpper())
                {
                    case "SCRIPT":
                        {
                            script = new SASScript(value);
                        } break;
                    case "SCRIPTCLASS":
                        {
                            switch (value)
                            {
                                case "OBJECT": scriptClass = ScriptClassType.Object; break;
                                case "SCENE": scriptClass = ScriptClassType.Scene; break;
                                case "OBJECTORSCENE": scriptClass = ScriptClassType.ObjectOrScene; break;
                            }
                        } break;
                    case "SCRIPTORDER":
                        {
                            switch (value)
                            {
                                case "STANDARD": scriptOrder = ScriptOrderType.Standard; break;
                            }
                        } break;
                    case "SCRIPTOUTPUT":
                        {
                            switch (value)
                            {
                                case "COLOR": scriptOutput = ScriptOutputType.Color; break;
                            }
                        } break;
                }
            }
            return true;
        }

        public bool Execute(SASMaterial sasEffect)
        {
            if (script != null)
            {
                SASScript.Context context = new SASScript.Context(
                    Engine.Instance.EffectEnvironment,
                    sasEffect,
                    null);

                return script.Execute(ref context);
            }

            return true;
        }
    }
    #endregion

    #region SASTransformParameter
    public class SASTransformParameter : SASParameter
    {
        protected enum Types
        {
            UNDEFINED,
            WORLD,
            VIEW,
            WORLDVIEW,
            VIEWPROJECTION,
            WORLDVIEWPROJECTION,
            WORLDINVERSE,
            VIEWINVERSE,
            PROJECTIONINVERSE,
            WORLDVIEWINVERSE,
            VIEWPROJECTIONINVERSE,
            WORLDVIEWPROJECTIONINVERSE,
            WORLDTRANSPOSE,
            VIEWTRANSPOSE,
            PROJECTIONTRANSPOSE,
            WORLDVIEWTRANSPOSE,
            VIEWPROJECTIONTRANSPOSE,
            WORLDVIEWPROJECTIONTRANSPOSE,
            WORLDINVERSETRANSPOSE,
            VIEWINVERSETRANSPOSE,
            PROJECTIONINVERSETRANSPOSE,
            WORLDVIEWINVERSETRANSPOSE,
            VIEWPROJECTIONINVERSETRANSPOSE,
            WORLDVIEWPROJECTIONINVERSETRANSPOSE,
        }
        private static Dictionary<string, Types> TransformTable = new Dictionary<string, Types>()
        {
            {"WORLD", Types.WORLD},
            {"VIEW", Types.VIEW},
            {"WORLDVIEW", Types.WORLDVIEW},
            {"VIEWPROJECTION", Types.VIEWPROJECTION},
            {"WORLDVIEWPROJECTION", Types.WORLDVIEWPROJECTION},
            {"WORLDINVERSE", Types.WORLDINVERSE},
            {"VIEWINVERSE", Types.VIEWINVERSE},
            {"PROJECTIONINVERSE", Types.PROJECTIONINVERSE},
            {"WORLDVIEWINVERSE", Types.WORLDVIEWINVERSE},
            {"VIEWPROJECTIONINVERSE", Types.VIEWPROJECTIONINVERSE},
            {"WORLDVIEWPROJECTIONINVERSE", Types.WORLDVIEWPROJECTIONINVERSE},
            {"WORLDTRANSPOSE", Types.WORLDTRANSPOSE},
            {"VIEWTRANSPOSE", Types.VIEWTRANSPOSE},
            {"PROJECTIONTRANSPOSE", Types.PROJECTIONTRANSPOSE},
            {"WORLDVIEWTRANSPOSE", Types.WORLDVIEWTRANSPOSE},
            {"VIEWPROJECTIONTRANSPOSE", Types.VIEWPROJECTIONTRANSPOSE},
            {"WORLDVIEWPROJECTIONTRANSPOSE", Types.WORLDVIEWPROJECTIONTRANSPOSE},
            {"WORLDINVERSETRANSPOSE", Types.WORLDINVERSETRANSPOSE},
            {"VIEWINVERSETRANSPOSE", Types.VIEWINVERSETRANSPOSE},
            {"PROJECTIONINVERSETRANSPOSE", Types.PROJECTIONINVERSETRANSPOSE},
            {"WORLDVIEWINVERSETRANSPOSE", Types.WORLDVIEWINVERSETRANSPOSE},
            {"VIEWPROJECTIONINVERSETRANSPOSE", Types.VIEWPROJECTIONINVERSETRANSPOSE},
            {"WORLDVIEWPROJECTIONINVERSETRANSPOSE", Types.WORLDVIEWPROJECTIONINVERSETRANSPOSE}
        };

        protected Types type;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.autoValue = true;
            this.type = Types.UNDEFINED;
            TransformTable.TryGetValue(parameter.Semantic.ToUpper(), out this.type);
            return true;
        }

        public override bool Update(SASEffectEnvironment environment)
        {
            switch (type)
            {
                case Types.WORLD:                   
                    {
                        MatrixValue = environment.world; 
                    } break;
                case Types.VIEW:                    
                    {
                        MatrixValue = environment.view; 
                    } break;
                case Types.WORLDVIEW:               
                    {
                        MatrixValue = environment.world * environment.view;
                    } break;
                case Types.VIEWPROJECTION:          
                    {
                        MatrixValue = environment.view * environment.projection; 
                    } break;
                case Types.WORLDVIEWPROJECTION:     
                    {
                        MatrixValue = environment.world * environment.view * environment.projection; 
                    } break;
                case Types.VIEWINVERSE:
                    {
                        Matrix ViewInverse;
                        Matrix.Invert(ref environment.view, out ViewInverse);
                        MatrixValue = ViewInverse;
                    } break;
                case Types.WORLDVIEWINVERSE:
                    {
                        Matrix WorldView = environment.world * environment.view;
                        Matrix WorldViewInverse;
                        Matrix.Invert(ref WorldView, out WorldViewInverse);
                        MatrixValue = WorldViewInverse;
                    } break;
                case Types.WORLDINVERSETRANSPOSE:   
                    {
                        Matrix WorldInverse;
                        Matrix WorldInverseTranspose;
                        Matrix.Invert(ref environment.world, out WorldInverse);
                        Matrix.Transpose(ref WorldInverse, out WorldInverseTranspose);
                        MatrixValue = WorldInverseTranspose;
                    } break;
                default: throw new NotImplementedException();
            }
            return true;
        }
    }
    #endregion

    #region SASTimeParameter
    public class SASTimeParameter : SASParameter
    {
        protected enum Types
        {
            UNDEFINED,
            ELAPSEDTIME,
            TIME
        }

        private static Dictionary<string, Types> TransformTable = new Dictionary<string, Types>()
        {
            {"ELAPSEDTIME", Types.ELAPSEDTIME},
            {"TIME", Types.TIME}
        };

        protected Types type;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.autoValue = true;
            this.type = Types.UNDEFINED;
            TransformTable.TryGetValue(parameter.Semantic.ToUpper(), out this.type);
            return true;
        }

        public override bool Update(SASEffectEnvironment environment)
        {
            switch (type)
            {
                case Types.ELAPSEDTIME:
                    {
                        FloatValue = environment.elapsedTime;
                    } break;
                case Types.TIME:
                    {
                        FloatValue = environment.time;
                    } break;
                default: throw new NotImplementedException();
            }

            return true;
        }
    }
    #endregion

    #region SASPositionParameter
    public class SASPositionParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.autoValue = true;
            this.target = new SASTarget(parameter);
            return true;
        }

        public override bool Update(SASEffectEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0:
                    {
                        VectorValue = environment.light0.position;
                    } break;
            }
            return true;
        }
    }
    #endregion

    #region SASSpecularParameter
    public class SASSpecularParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.autoValue = true;
            this.target = new SASTarget(parameter);
            return true;
        }

        public override bool Update(SASEffectEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0:
                    {
                        VectorValue = environment.light0.specular;
                    } break;
            }
            return true;
        }
    }
    #endregion

    #region SASAmbientParameter
    public class SASAmbientParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.autoValue = true;
            this.target = new SASTarget(parameter);
            return true;
        }

        public override bool Update(SASEffectEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0:
                    {
                        VectorValue = environment.light0.ambient;
                    } break;
            }
            return true;
        }
    }
    #endregion

    #region SASDepthStencilParameter
    public class SASDepthStencilParameter : SASParameter
    {
        protected DepthStencilBuffer currentBuffer = null;
        internal DepthStencilBuffer CurrentBuffer { get { return currentBuffer; } }

        protected DepthStencilBuffer previousBuffer = null;
        internal DepthStencilBuffer PreviousBuffer { get { return previousBuffer; } set { previousBuffer = value; } }

        protected DepthFormat depthFormat = DepthFormat.Depth24Stencil8;
        protected Vector2 viewportRatio = new Vector2(1.0f, 1.0f);
        protected Vector2 dimensions = new Vector2(128.0f, 128.0f);

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);

            if (parameter.ParameterType != EffectParameterType.Texture)
            {
                throw new Exception(string.Format("{0} semantic is only valid with texture parameters", parameter.Semantic));
            }

            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                switch (annotation.Name.ToUpper())
                {
                    case "VIEWPORTRATIO":
                        {
                            viewportRatio = annotation.GetValueVector2();
                        } break;
                    case "DIMENSIONS":
                        {
                            dimensions = annotation.GetValueVector2();
                        } break;
                    case "FORMAT":
                        {
                            switch (annotation.GetValueString().ToUpper())
                            {
                                case "D24S8": depthFormat = DepthFormat.Depth24Stencil8; break; 
                            }
                        } break;
                }
            }

            return true;
        }

        internal bool LoadDepthStencilBuffer(GraphicsDevice gd)
        {
            UnloadDepthStencilBuffer();

            previousBuffer = null;
            currentBuffer = new DepthStencilBuffer(
                    gd,
                    (int)(viewportRatio != null ? (gd.Viewport.Width * viewportRatio.X) : dimensions.X),
                    (int)(viewportRatio != null ? (gd.Viewport.Height * viewportRatio.Y) : dimensions.Y),
                    depthFormat 
                );

            return (currentBuffer != null);
        }

        internal bool UnloadDepthStencilBuffer()
        {
            if (currentBuffer != null)
            {
                currentBuffer.Dispose();
                return true;
            }

            previousBuffer = null;

            return false;
        }
    }
    #endregion

    #region SASRenderTargetParameter
    public class SASRenderTargetParameter : SASParameter
    {
        protected RenderTarget2D renderTarget = null;
        internal RenderTarget2D RenderTarget { get { return renderTarget; } }

        protected SurfaceFormat surfaceFormat = SurfaceFormat.Color;
        protected Vector2 viewportRatio = new Vector2(1.0f, 1.0f);
        protected Vector2 dimensions = new Vector2(128.0f, 128.0f);
        protected int mipLevels = 1;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);

            if (parameter.ParameterType != EffectParameterType.Texture) 
            {
                throw new Exception(string.Format("{0} semantic is only valid with texture parameters", parameter.Semantic));
            }

            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                switch (annotation.Name.ToUpper())
                {
                    case "VIEWPORTRATIO":
                        {
                            viewportRatio = annotation.GetValueVector2();
                        } break;
                    case "DIMENSIONS":
                        {
                            dimensions = annotation.GetValueVector2();
                        } break;
                    case "FORMAT": 
                        {
                            switch (annotation.GetValueString().ToUpper())
                            {
                                case "R8G8B8": surfaceFormat = SurfaceFormat.Color; break;
                                case "A8R8G8B8": surfaceFormat = SurfaceFormat.Color; break;
                                case "X8R8G8B8": surfaceFormat = SurfaceFormat.Color; break;
                            }
                        } break;
                }
            }

            return true;
        }

        internal bool LoadRenderTarget(GraphicsDevice gd)
        {
            UnloadRenderTarget();

            renderTarget = new RenderTarget2D(
                    gd,
                    (int) (viewportRatio != null ? (gd.Viewport.Width * viewportRatio.X) : dimensions.X),
                    (int) (viewportRatio != null ? (gd.Viewport.Height * viewportRatio.Y) : dimensions.Y),
                    mipLevels,
                    surfaceFormat
                );

            return (renderTarget != null);
        }

        internal bool UnloadRenderTarget()
        {
            if (renderTarget != null)
            {
                renderTarget.Dispose();
                return true;
            }

            return false;
        }
    }
    #endregion

    #region SASViewportPixelSizeParameter
    public class SASViewportPixelSizeParameter : SASParameter
    {
        public override bool Initialize(EffectParameter parameter)
        {
            bool result = base.Initialize(parameter);

            VectorValue = new Vector4(
                Engine.Instance.GraphicsDevice.Viewport.Width,
                Engine.Instance.GraphicsDevice.Viewport.Height,
                1.0f, 1.0f);

            return result;
        }
    }
    #endregion
}
